﻿/**
 * @file service_logger.hpp
 * @date 2021/04/15 20:16
 *
 * @author harrybao (harrybao@123u.com)
 *
 * @brief 服务日志
 *
 * @version v1.0.0
 *
 * @copyright Copyright © 2021 All Rights Reserved 上海欢乐互娱网络科技有限公司
 *
 * @par history:
 * <table>
 * <tr><th>Date                     <th>Version     <th>Author <th>Description
 * <tr><td>2021/04/15 20:16         <td>1.0.0       <td>harrybao
 * <td>创建初始版本
 * </table>
 */

// #ifndef SERVICE_LOGGER_H
// #define SERVICE_LOGGER_H

#pragma once

#include <cstdarg>
#include <cstdio>

#include "box/service_context.hh"
#include "box/service_logger.hh"
#include "klogger/interface/logger.h"
#include "service_tool.hpp"
#include "singleton.hpp"


namespace guild_service {
namespace common {

/**
 * @brief 服务日志类
 *
 */
class service_logger : public service_tool {
 public:
  using service_context_type = kratos::service::ServiceContext;
  using logger_ptr_type = kratos::service::LoggerPtr;
  using logger_type = kratos::service::ServiceLogger;
  using logger_level_type = klogger::Logger;

  service_logger() : service_tool(), m_logger(nullptr) {}

  service_logger(service_context_type* context, const std::string& service_name)
      : service_tool(),
        m_logger(std::move(context->get_module_logger(service_name))) {}

  ~service_logger() = default;

  /**
   * @brief
   *
   * @return logger_type*
   */
  logger_type* operator->() { return m_logger.get(); }

  /**
   * @brief
   *
   * @return logger_type&
   */
  logger_type& operator*() { return *m_logger.get(); }

 private:
  ///
  logger_ptr_type m_logger;
};

}  // namespace common

#define ServiceLoggerSingleton(...) \
  (*common::singleton<common::service_logger>::instance(__VA_ARGS__))

inline static void log_debug(const std::string& s) {
  ServiceLoggerSingleton()->debug_log(s);
}

inline static void log_info(const std::string& s) {
  ServiceLoggerSingleton()->info_log(s);
}

inline static void log_warn(const std::string& s) {
  ServiceLoggerSingleton()->warn_log(s);
}

inline static void log_except(const std::string& s) {
  ServiceLoggerSingleton()->except_log(s);
}

inline static void log_fail(const std::string& s) {
  ServiceLoggerSingleton()->fail_log(s);
}

inline static common::service_logger::logger_type& log_debug() {
  return (*ServiceLoggerSingleton()).debug();
}

inline static common::service_logger::logger_type& log_info() {
  return (*ServiceLoggerSingleton()).info();
}

inline static common::service_logger::logger_type& log_warn() {
  return (*ServiceLoggerSingleton()).warn();
}

inline static common::service_logger::logger_type& log_except() {
  return (*ServiceLoggerSingleton()).except();
}

inline static common::service_logger::logger_type& log_fail() {
  return (*ServiceLoggerSingleton()).fail();
}

using logger_level_type =
    guild_service::common::service_logger::logger_level_type;  ///< 日志等级类型

inline static int do_log_it(int log_level, const char* format, ...) {
  static char buffer[1024];

  int result;

  va_list va_ptr;
  va_start(va_ptr, format);
  result = vsnprintf(buffer, sizeof(buffer), format, va_ptr);
  // result = vsprintf(buffer, format, va_ptr);
  va_end(va_ptr);

  if (result < 0) {
    return result;
  }

  switch (log_level) {
    case logger_level_type::DIAGNOSE:
      log_debug(std::string(buffer));
      break;
    case logger_level_type::INFORMATION:
      log_info(std::string(buffer));
      break;
    case logger_level_type::WARNING:
      log_warn(std::string(buffer));
      break;
    case logger_level_type::EXCEPTION:
      log_except(std::string(buffer));
      break;
    case logger_level_type::FAILURE:
      log_fail(std::string(buffer));
      break;
    default:
      break;
  }

  return result;
}

template <typename... Args>
inline static int log_it(int log_level, const char* format, Args... args) {
  return do_log_it(log_level, format, std::forward<Args>(args)...);
}

#include <string>
//#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 :
//__FILE__)
#define __FILENAME__ (strrchr("/" __FILE__, '/') + 1)

#define LOG_DEBUG(format, ...)                                      \
  guild_service::log_it(guild_service::logger_level_type::DIAGNOSE, \
                        " " format " - %s(%s:%d) ", ##__VA_ARGS__,  \
                        __FUNCTION__, __FILENAME__, __LINE__)
#define LOG_INFO(format, ...)                                          \
  guild_service::log_it(guild_service::logger_level_type::INFORMATION, \
                        " " format " - %s(%s:%d) ", ##__VA_ARGS__,     \
                        __FUNCTION__, __FILENAME__, __LINE__)
#define LOG_WARN(format, ...)                                      \
  guild_service::log_it(guild_service::logger_level_type::WARNING, \
                        " " format " - %s(%s:%d) ", ##__VA_ARGS__, \
                        __FUNCTION__, __FILENAME__, __LINE__)
#define LOG_EXCEPT(format, ...)                                      \
  guild_service::log_it(guild_service::logger_level_type::EXCEPTION, \
                        " " format " - %s(%s:%d) ", ##__VA_ARGS__,   \
                        __FUNCTION__, __FILENAME__, __LINE__)
#define LOG_FAIL(format, ...)                                      \
  guild_service::log_it(guild_service::logger_level_type::FAILURE, \
                        " " format " - %s(%s:%d) ", ##__VA_ARGS__, \
                        __FUNCTION__, __FILENAME__, __LINE__)

#define LOG_BEGIN_S \
  " - " << __func__ << " " << __FILENAME__ << ":" << __LINE__ << " "

#define LOG_DEBUG_S guild_service::log_debug() << LOG_BEGIN_S
#define LOG_INFO_S guild_service::log_info() << LOG_BEGIN_S
#define LOG_WARN_S guild_service::log_warn() << LOG_BEGIN_S
#define LOG_EXCEPT_S guild_service::log_except() << LOG_BEGIN_S
#define LOG_FAIL_S guild_service::log_fail() << LOG_BEGIN_S

#define LOG_END_S kratos::service::EndLog()

}  // namespace guild_service

// #endif  // SERVICE_LOGGER_H